Bringing the Language Server Protocol to Jupyter(Lab)
.. rubric:: ⸻ @krassowski, @bollwyvl :name: krassowski-bollwyvlWhat is the Language Server Protocol?¶
A Language Server is meant to provide the language-specific smarts and communicate with **development tools* over a protocol that enables inter-process communication.*
The idea behind the Language Server Protocol (LSP) is to standardize the protocol for how such **servers* and development tools communicate. This way, a single Language Server can be re-used in multiple development tools, which in turn can support multiple languages with minimal effort.*
⸻ microsoft.github.io/language-server-protocol
*emphasis ours*
But Practically…¶
markdown specification (on the above site)
reference server,
vscode-language-server-node
reference client,
vscode
number of other clients
What is a Language Server?¶
a process that speaks JSON-RPC 2.0 over
stdin
/stdout
(or sometimes TCP)the messages are things like
🙋 I opened a file!
🤖 YOUR FILE HAS TRAILING WHITESPACE
🙋 I fixed some whitespace
🤖 THERE IS NOTHING WRONG NOW
🙋 I hovered over a symbol!
🤖 IT’S A FUNCTION
🙋 Where did it come from?
🤖 THIS OTHER FILE OVER HERE
Sounds a lot like the Jupyter Message Spec¶
Yep
But it’s good to have both
Kernel (usually) does dynamic analysis, so can do More Things
Language Server (usually) does static analysis, so (usually) faster
Also, it doesn’t make sense to have Kernels for some things
Future kernels could contribute their own LSP messages
SPOOKY DEMO
[6]:
pumpkins = "🎃" * 10
pumpkins + "more pumpkins"
[6]:
'🎃🎃🎃🎃🎃🎃🎃🎃🎃🎃more pumpkins'
[ ]:
pumpkins + 2
[8]:
Chicken = 0
chicken = {
chicken for chicken in range(10)
if chicken in [Chicken]
}
[10]:
# this_variable_is_not_used - 1
What have we done on [@krassowski/jupyterlab-lsp](https://github.com/krassowski/jupyterlab-lsp)¶
Reuse existing LSP <-> CodeMirror bridge
Implement
Jump to Definition
TypeScript Unit tests on Travis CI
Traitnado-based LSP WebSocket proxy
Python Unit tests and Browser tests on Azure Pipelines
Upstream PRs
yaml-language-server
conda-forge (for
r-languageserver
)void
on
Next Steps¶
Keep putting out releases people can try out
Keep heading towards proposal to JupyterLab core
Encourage some contributors
Add/Test more Language Servers (and Features)
Warm up the JEP PR #26
[ ]:
%%file spooky.csscss
@import url('https://fonts.googleapis.com/css?family=Lakki+Reddy&display=swap');
#main {
--jp-border-width: 0.01px;
--pumpkin: rgba(245, 124, 0, 0.75);
--ghost: rgba(255, 255, 255, 0.5);
}
#main .cm-lsp-highlight:not(:empty) {
background-color: var(--pumpkin);
border-radius: 5px;
color: yellow !important;
text-shadow: 0 0 5px yellow;
padding: 0.25em 0;
font-weight: bold;
position: relative;
border-left: none;
border-right: none;
transition: all 1s;
}
.cm-lsp-highlight:not(:empty)::before {
content: '🍃';
font-size: 0.9em;
top: -0.9em;
left: 50%;
color: green;
position: absolute;
text-shadow: none;
transition: all 1s;
}
#main
.cm-lsp-diagnostic-Error:not(.cm-lsp-highlight):not(.cm-lsp-highlight-Write) {
color: black !important;
background-color: var(--ghost);
border-radius: 1em 1em 0 0;
font-weight: bold;
padding: 0.25em 0.25em 0.1em 0.25em;
position: relative;
text-decoration-color: transparent;
margin: 0 0.2em;
transition: all 1s;
}
.cm-lsp-diagnostic-Error:not(.cm-lsp-highlight):not(.cm-lsp-highlight-Write):before {
position: absolute;
left: 0;
right: 0;
top: -10%;
height: 110%;
border-bottom: dotted 2px var(--ghost) !important;
content: '';
transition: all 1s;
}
#main
.cm-lsp-diagnostic-Warning:not(.cm-lsp-highlight-Write):not(.cm-lsp-diagnostic-Error) {
position: relative;
color: green;
font-weight: bold;
text-shadow: 0 0 10px green;
text-decoration: none;
font-size: 2em;
-webkit-text-stroke: 1px rgba(0, 50, 0, 0.5);
font-family: 'Lakki Reddy', cursive;
transition: all 1s;
}
body .jp-HoverBox {
min-width: 300px;
overflow-y: auto;
}
body .jp-HoverBox,
body .jp-HoverBox * {
background-color: black !important;
color: red !important;
font-family: 'Lakki Reddy', cursive;
font-size: 16px !important;
text-align: center;
font-weight: bold;
}
[2]:
import pathlib
import IPython
css = pathlib.Path("spooky.css").read_text()
IPython.display.HTML(f"<style>{css}</style>")
[2]: